package xyz.ziduo.lapcounter;

import androidx.appcompat.app.AppCompatActivity;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbRequest;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.concurrent.Semaphore;

public class TestActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "LC: " + MainActivity.class.getSimpleName();

    private static final String ACTION_USB_PERMISSION = "xyz.ziduo.lapcounter.USB_PERMISSION";
    private UsbManager usbManager;
    private PendingIntent permissionIntent;

    TextView tv_tip;
    Button btn_test;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);

        usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
        int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_MUTABLE : 0;
        permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), flags);

        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        registerReceiver(usbReceiver, filter);

        tv_tip = findViewById(R.id.tv_tip);
        btn_test = findViewById(R.id.btn_test);
        btn_test.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                requestPermission();
            }
        });
    }

    @Override
    public void onClick(View view) {
        if(isFastClick()) return; // 如果是快速点击则不进行响应
        if(view.getId() == R.id.btn_test) {
            Log.i(TAG, "========= onClick: btn_test");
            //open();
            //requestPermission();
        }
    }

    // 请求USB设备权限
    private void requestPermission() {
        // 获取已连接的USB设备列表
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        Log.e(TAG, "dev num = " + deviceList.size());
        for(UsbDevice device : deviceList.values()) {
            /* 用于打印设备信息
            int vID = device.getVendorId();
            String deviceName = device.getDeviceName();
            String productName = device.getProductName();
            int pID = device.getProductId();
            int dID = device.getDeviceId();
            Log.e(TAG, "======  vID = " + vID);
            Log.e(TAG, "productName = " + productName);
            Log.e(TAG, "pID = " + pID);
            Log.e(TAG, "deviceName = " + deviceName);
            Log.e(TAG, "dID = " + dID);
            // */
            // 检查设备是否有权限
            /*if(!usbManager.hasPermission(device)) {
                //Log.e(TAG, " 无权限 ");
                // 请求权限
                usbManager.requestPermission(device, permissionIntent);
            }*/
            usbManager.requestPermission(device, permissionIntent);
        }
    }

    // USB设备权限广播接收器
    private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if(ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    if(intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                        if(device != null) {
                            Log.e(TAG, "  dev != null  ");
                            open(device);
                            // 打开USB设备
                            // UsbDeviceConnection connection = usbManager.openDevice(device);

                        } else {
                            Log.e(TAG, " dev = null ");
                        }
                    } else {
                        Log.e(TAG, "USB permission denied.");
                    }
                }
            }
        }
    };

    private void open(UsbDevice device) {
        // 查找启动接口
        UsbInterface usbInterface = null;
        for(int i=0; i<device.getInterfaceCount(); ++i) {
            UsbInterface interf = device.getInterface(i);
            if(interf.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
                    interf.getInterfaceSubclass() == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT &&
                    interf.getInterfaceProtocol() == UsbConstants.USB_CLASS_COMM) {
                usbInterface = interf;
                break;
            }
        }
        //打开设备
        UsbDeviceConnection connection = usbManager.openDevice(device);
        if(connection == null) {
            Log.e(TAG, " connection == null");
            return;
        }
        if(!connection.claimInterface(usbInterface, true)) {
            Log.e(TAG, " claimInterface failed");
            return;
        }
        //查找输入输出端点
        UsbEndpoint endpointIn = null, endpointOut = null;
        int inEndpointMaxPacketSize = 0, outEndpointMaxPacketSize = 0;
        for(int i=0; i<usbInterface.getEndpointCount(); ++i) {
            UsbEndpoint endpoint = usbInterface.getEndpoint(i);
            if(endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                if(endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
                    endpointIn = endpoint;
                    inEndpointMaxPacketSize = endpointIn.getMaxPacketSize();
                } else {
                    endpointOut = endpoint;
                    outEndpointMaxPacketSize = endpointOut.getMaxPacketSize();
                }
            }
        }
        if(endpointIn == null || endpointOut == null) {
            Log.e(TAG, "endpointIn or endpointOut is null");
            return;
        }
        Log.e(TAG, String.format("inEndpointMaxPacketSize = %d, outEndpointMaxPacketSize = %d", inEndpointMaxPacketSize, outEndpointMaxPacketSize));
        Log.e(TAG, "device is connected.");
        // 连接上后设置成空usb
        // 查找请求类
        UsbRequest[] usbRequestSet = new UsbRequest[20]; // 20就是自己设置的一个数：REQUEST_COUNT
        ByteBuffer[] readByteBufferSet = new ByteBuffer[20];
        for(int i=0; i<20; ++i) {
            UsbRequest request = new UsbRequest();
            request.initialize(connection, endpointIn);
            usbRequestSet[i] = request;
            readByteBufferSet[i] = ByteBuffer.allocate(32 * 4);
        }
        // 初始化UART
        if(!uartInit(connection)) {
            Log.e(TAG, "uartInit failed.");
            return;
        }
        Log.e(TAG, "uartInit successed.");
        // 将缓冲加入到队列中，以接收数据
        for(int i=0; i<20; ++i) {
            usbRequestSet[i].queue(readByteBufferSet[i]);
        }
        mUsbReadThread = new UsbReadThread(connection, usbRequestSet, readByteBufferSet);
        mUsbReadThread.start();

        /*UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(device);
        if(driver == null) {
            Log.e(TAG, " driver == null ");
            Log.e(TAG, " productName = " + device.getProductName());
            ProbeTable table = new ProbeTable();
            table.addProduct(6790, 29986, FtdiSerialDriver.class);
            driver = new UsbSerialProber(table).probeDevice(device);
            if(driver == null) {
                Log.e(TAG, " driver == null still");
            } else {
                Log.e(TAG, " driver != null still");
                Log.e(TAG, " port.size = " + driver.getPorts().size());
                UsbSerialPort usbSerialPort = driver.getPorts().get(0);
                UsbDeviceConnection usbConnection = usbManager.openDevice(driver.getDevice());
                if(usbConnection == null) {
                    Log.e(TAG, " usbConnection == null");
                } else {
                    Log.e(TAG, " usbConnection != null");
                }
            }
        } else {
            Log.e(TAG, " driver != null ");
        }*/

    }

    private UsbReadThread mUsbReadThread;
    private class UsbReadThread extends Thread {
        private volatile boolean stop = false;
        private UsbDeviceConnection usbDeviceConnection;
        private UsbRequest[] requestSet;
        private ByteBuffer[] readByteBufferSet;
        private Semaphore semaphore = new Semaphore(1);
        public UsbReadThread(UsbDeviceConnection usbDeviceConnection, UsbRequest[] requestSet, ByteBuffer[] readByteBufferSet) {
            //this.usbSerialPort = usbSerialPort;
            this.usbDeviceConnection = usbDeviceConnection;
            this.requestSet = requestSet;
            this.readByteBufferSet = readByteBufferSet;
        }
        public void doStop() {
            stop = true;
        }
        @Override
        public void run() {
            StringBuilder stringBuilder = new StringBuilder();
            byte[] lineBuff = new byte[1024];
            int lineInd = 0;
            while (!stop) {
                for(int i=0; i<20; ++i) {
                    UsbRequest request = usbDeviceConnection.requestWait();
                    if(request == null) {
                        Log.e(TAG, "mUsbReadThread request == null");
                        break;
                    }
                    UsbRequest request1 = requestSet[i];
                    if(request != request1) {
                        Log.e(TAG, "mUsbReadThread request == request1");
                        continue;
                    }
                    ByteBuffer buffer = readByteBufferSet[i];
                    byte[] buff = buffer.array();
                    int len = buffer.position();
                    if(len > 0) {
                        try {
                            semaphore.acquire();
                            for(int j=0; j<len; ++j) {
                                byte bt = buff[j];
                                if(bt == 0x0a) { // 遇到换行符
                                    String line = new String(lineBuff, 0, lineInd, StandardCharsets.UTF_8);
                                    stringBuilder.append(line).append("\n");
                                    Log.e(TAG, "amk = " + line);
                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            //tv_tip.setText(line);
                                        }
                                    });
                                    lineInd = 0;
                                } else {
                                    lineBuff[lineInd ++] = bt;
                                }
                            }
                        } catch (InterruptedException ie) {
                            stop = true;
                        } finally {
                            semaphore.release();
                        }
                    }
                    request.queue(buffer);
                }
            }

            /*if(usbSerialPort == null || usbDeviceConnection == null) throw new RuntimeException("DataThread: 无设备");
            try {
                usbSerialPort.open(usbDeviceConnection);
                try{
                    usbSerialPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
                }catch (UnsupportedOperationException e){
                    Log.e(TAG, " unsupport setparameters");
                }
                Log.e(TAG, " connect ok");
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_tip.setText(tv_tip.getText() + "\n" + "connect ok");
                    }
                });
            } catch (Exception e) {
                Log.e(TAG, "connection failed: " + e.getMessage(), e);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_tip.setText(tv_tip.getText() + "\n" + "connection failed\n" + e.getMessage());
                    }
                });
            }*/
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mUsbReadThread != null) mUsbReadThread.doStop();
        unregisterReceiver(usbReceiver);
    }

    /**
     * 设置初始化CH34x芯片
     *
     * @return 若初始化失败，则返回 false，成功返回 true
     */
    public static boolean uartInit(UsbDeviceConnection connection) {
        byte[] var = new byte[8];
        controlTransfer(connection, 161, 0, 0);
        if (controlTransfer(connection, 95, 0, 0, var, 2) < 0) {
            return false;
        } else {
            controlTransfer(connection, 154, 4882, 55682);
            controlTransfer(connection, 154, 3884, 4);
            if (controlTransfer(connection, 149, 9496, 0, var, 2) < 0) {
                return false;
            } else {
                controlTransfer(connection, 154, 10023, 0);
                controlTransfer(connection, 164, 255, 0);
            }
        }
        Log.e(TAG, "set uart parameters");
        // 设置波特率
        char c2;
        int i2;
        int i3;
        c2  = 3;
        i2 = 3;
        i3 = 204;
        int i4 = 156 | (((char) (c2 | 192)) << '\b');
        int m2a = controlTransfer(connection, 161, i4, 0 | 136 | i2 | (i3 << 8));
        return m2a >= 0;
    }

    private static int controlTransfer(UsbDeviceConnection connection, int i, int i2, int i3) {
        int initTimeOut = 1000;
        return connection.controlTransfer(64, i, i2, i3, null, 0, initTimeOut);
    }
    private static int controlTransfer(UsbDeviceConnection connection, int i, int i2, int i3, byte[] bArr, int i4) {
        int initTimeOut = 1000;
        return connection.controlTransfer(192, i, i2, i3, bArr, 2, initTimeOut);
    }

    // 按钮的点击时间
    private long mClickTime;
    // 判断是否为快速点击
    private boolean isFastClick() {
        long clickTime = System.currentTimeMillis();
        if(clickTime - mClickTime > 200) { // 点击间隔超 200ms 则认为不是快速点击
            mClickTime = clickTime;
            return false;
        }
        return true;
    }
}